#include "ParseTableBuilder.h"
#include <iostream>

ParseTableBuilder::ParseTableBuilder(const Grammar& grammar) : grammar_(grammar) {}

void ParseTableBuilder::build() {
    for (const auto& entry : grammar_.getProductions()) {
        const Symbol& A = entry.first;
        const auto& prods = entry.second;

        for (const auto& prod : prods) {
            std::unordered_set<Symbol> firstSet;
            bool canBeEpsilon = true;

            for (const auto& sym : prod) {
                const auto& symFirst = grammar_.getFirst(sym);
                for (const auto& t : symFirst) {
                    if (t != "epsilon")
                        firstSet.insert(t);
                }
                if (symFirst.count("epsilon") == 0) {
                    canBeEpsilon = false;
                    break;
                }
            }

            for (const auto& t : firstSet) {
                parseTable_[A][t] = prod;
            }

            if (canBeEpsilon) {
                const auto& followA = grammar_.getFollow(A);
                for (const auto& t : followA) {
                    parseTable_[A][t] = prod;
                }
            }
        }
    }
}

void ParseTableBuilder::print() const {
    for (const auto& row : parseTable_) {
        const Symbol& nonTerminal = row.first;
        for (const auto& cell : row.second) {
            const Symbol& terminal = cell.first;
            const auto& prod = cell.second;

            std::cout << "M[" << nonTerminal << "][" << terminal << "] = "
                      << nonTerminal << " -> ";
            for (const auto& s : prod)
                std::cout << s << " ";
            std::cout << "\n";
        }
    }
}

const std::unordered_map<ParseTableBuilder::Symbol, std::unordered_map<ParseTableBuilder::Symbol, ParseTableBuilder::Production>>&
ParseTableBuilder::getTable() const {
    return parseTable_;
}
